#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>

#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include "linux/io.h"

struct device_test {
    dev_t dev_num;              // 设备号
    int major;                  // 主设备号
    int minor;                  // 次设备号
    struct cdev cdev_test;      // 字符设备
    struct class *class;        // 类
    struct device *device;      // 设备

    char kbuf[32];              // 缓存区buf 
    unsigned int *vir_gpio_dr;  // 虚拟GPIO数据寄存器
};

// 定义设备
struct device_test dev1;

/* 打开设备函数*/
static int cdev_open(struct inode *inode, struct file *file)
{
    //inode->i_rdev为该inode的字符设备，

    // 使用container_of函数通过字符设备找到设备结构体变量dev1的地址,并设置为私有数据
    file->private_data = container_of(inode->i_cdev, struct device_test, cdev_test);

    printk(KERN_EMERG "This is cdev_open\r\n");
    return 0;
}

/* 向设备写数据函数*/
static ssize_t cdev_write(struct file *file, const char __user *buff, size_t size, loff_t * off)
{
    struct device_test *test_dev = (struct device_test *)file->private_data;

    // 用户向内核空间传递数据
    if (copy_from_user(test_dev->kbuf, buff, size) != 0)
    {
        printk(KERN_EMERG "copy_from_user error\r\n");
        return -1;
    }

    if (test_dev->kbuf[0] == '0')
    {
        *(test_dev->vir_gpio_dr) = 0x00010000;
        printk(KERN_EMERG "led off\n");
    } else if (test_dev->kbuf[0] == '1')
    {
        *(test_dev->vir_gpio_dr) = 0x00010001;
        printk(KERN_EMERG "led on\n");
    }

    printk(KERN_EMERG "cdev_write kbuf size : %ld\r\n", size);
    printk(KERN_EMERG "kbuf: %s\r\n", test_dev->kbuf);

    return 0;
}

/* 从设备读数据 函数 */
static ssize_t cdev_read(struct file *file, char __user *buff, size_t size, loff_t *off)
{
    struct device_test *test_dev = (struct device_test *)file->private_data;

    // 内核 向 用户空间传递数据
    if (copy_to_user(buff, test_dev->kbuf, size) != 0)
    {
        printk(KERN_EMERG "copy_to_user error\r\n");
        return -1;
    }
    printk(KERN_EMERG "This is cdev_read\r\n");
    return 0;
}


static int cdev_release (struct inode *inode, struct file *file)
{
    printk(KERN_EMERG "This is cdev_release\r\n");
    return 0;
}


struct file_operations cdev_fops = {
    .owner = THIS_MODULE,
    .open = cdev_open,
    .read = cdev_read,
    .write = cdev_write,
    .release = cdev_release,
};


// 平台设备探测函数
// 当系统检测到一个平台设备与该驱动程序匹配时，该 函数将被调用以初始化和配置设备。  
int my_platform_probe(struct platform_device *pdev)
{
    struct resource *res_mem;
    struct resource *res_irq;
    int ret;

    printk(KERN_EMERG "my_platform_probe: Probing platform device!\n");
    /* 设备特定操作 */

    // // 方法1直接访问 platform_device *pdev
    // if (pdev->num_resources >= 2)
    // {
    //     // 局部变量
    //     struct resource *res_mem = &pdev->resource[0];
    //     struct resource *res_irq = &pdev->resource[1];

    //     printk(KERN_EMERG "Method 1: MEM [0x%llx --- 0x%llx]\n", res_mem->start, res_mem->end);
    //     printk(KERN_EMERG "Method 1: IRQ [%lld]\n", res_irq->start);
    // }

    // 方法2, 通过platform_get_resource()函数获取
    res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res_mem)
    {
        dev_err(&pdev->dev, "Failed to get memory resource\n");
        return -ENODEV;
    }
    res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (!res_irq)
    {
        dev_err(&pdev->dev, "Failed to get IRQ resource\n");
        return -ENODEV;
    }
    printk(KERN_EMERG "Method 2: MEM [0x%llx --- 0x%llx]\n", res_mem->start, res_mem->end);
    printk(KERN_EMERG "Method 2: IRQ [%lld]\n", res_irq->start);

    // 注册字符设备驱动
    // 注册设备号
    ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name");
    if (ret < 0)
    {
        printk(KERN_EMERG "alloc chrdev is error\n");
        goto err_cdev_region;
    }
    printk(KERN_EMERG "alloc chrdev is ok\n");
    dev1.major = MAJOR(dev1.dev_num);
    dev1.minor = MINOR(dev1.dev_num);
    printk(KERN_EMERG "major = %d  | minor = %d\n", dev1.major, dev1.minor);



    // 初始化，添加字符设备到内核
    dev1.cdev_test.owner = THIS_MODULE;
    cdev_init(&dev1.cdev_test, &cdev_fops);
    ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
    if (ret < 0)
    {
        goto err_cdev_add;
    }


    // 创建类和设备节点
    dev1.class = class_create(THIS_MODULE, "gpio_test");
    if (IS_ERR(dev1.class))
    {
        ret = PTR_ERR(dev1.class);
        goto err_class_create;
    }
    dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "gpio_test");
    if (IS_ERR(dev1.device))
    {
        ret = PTR_ERR(dev1.device);
        goto err_device_create;
    }


    /* GPIO 内存映射*/
    dev1.vir_gpio_dr = ioremap(res_mem->start, 4);
    if (IS_ERR(dev1.vir_gpio_dr))
    {
        ret = PTR_ERR(dev1.vir_gpio_dr);
        goto err_ioremap;
    }

    return 0;

err_ioremap:
    iounmap(dev1.vir_gpio_dr);                      // 取消内存映射
    device_destroy(dev1.class, dev1.dev_num);       // 删除设备节点
err_device_create:
    class_destroy(dev1.class);                      // 删除类
err_class_create:    
    cdev_del(&dev1.cdev_test);                      // 删除字符设备
err_cdev_add:
    unregister_chrdev_region(dev1.dev_num, 1);      // 删除设备号
err_cdev_region:
    return ret;                                     // 返回错误码


    return 0;
}

// 平台设备移除函数
// 当平台设备从系统中移除时，该函数将被调用以执行 清理和释放资源的操作。
int my_platform_remove(struct platform_device *pdev)
{
    printk(KERN_EMERG "my_platform_remove: Remove platform device!\n");
    /* 设备特定操作 */
    iounmap(dev1.vir_gpio_dr);                      // 取消内存映射
    device_destroy(dev1.class, dev1.dev_num);       // 删除设备节点
    class_destroy(dev1.class);                      // 删除类
    cdev_del(&dev1.cdev_test);                      // 删除字符设备
    unregister_chrdev_region(dev1.dev_num, 1);      // 删除设备号

    return 0;
}

// 平台设备关闭函数
// 当系统关闭时，该函数将被调用以执行与平台设备 相关的关闭操作。 
void my_platform_shutdown(struct platform_device *pdev)
{
    printk(KERN_EMERG "my_platform_shutdown: Shutdown platform device!\n");
    /* 设备特定操作 */

    
}
// 平台设备挂起函数
// 当系统进入挂起状态时，该函数将被调用以执行与 平台设备相关的挂起操作。
int my_platform_suspend(struct platform_device *pdev, pm_message_t state)
{
    printk(KERN_EMERG "my_platform_suspend: Suspend platform device!\n");
    /* 设备特定操作 */

    return 0;
}
// 平台设备恢复函数
// 当系统从挂起状态恢复时，该函数将被调用以执行与 平台设备相关的恢复操作。  
int my_platform_resume(struct platform_device *pdev)
{
    printk(KERN_EMERG "my_platform_resume: Resume platform device!\n");
    /* 设备特定操作 */

    return 0;
}



static struct platform_driver my_platform_driver = {
    .probe = my_platform_probe,
    .remove = my_platform_remove,
    .shutdown = my_platform_shutdown,
    .suspend = my_platform_suspend,
    .resume = my_platform_resume,

    .driver = {
        .name = "my_platform_GPIO",
        .owner = THIS_MODULE,
    },
};


static int __init my_platform_device_init(void)
{   
    int ret;

    // 注册平台驱动
    ret = platform_driver_register(&my_platform_driver);
     if (ret < 0)
    {
        printk(KERN_EMERG "Failed platform_driver_register.\n");
        return ret;
    }

    printk(KERN_EMERG "platform_driver_register OK!\n");

    return 0;
}



static void __exit my_platform_device_exit(void)
{
    platform_driver_unregister(&my_platform_driver);// 注销平台驱动
    printk(KERN_EMERG "platform_driver_unregister OK!\n");
}



module_init(my_platform_device_init);
module_exit(my_platform_device_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Treasure1029");










